<template>
  <div class="digital-human-container">
    <div class="header-section">
      <h1 class="title">数字人功能</h1>
      <div class="development-badge">功能开发中</div>
      <p class="subtitle">高级虚拟数字人助手，为您提供个性化的购车咨询体验</p>
    </div>
    
    <div class="feature-content">
      <div class="feature-grid">
        <div class="feature-card">
          <div class="icon-container">
            <i class="el-icon-s-custom"></i>
          </div>
          <h3>AI数字形象</h3>
          <p>真人3D建模，面部表情自然，实时互动反馈</p>
        </div>
        
        <div class="feature-card">
          <div class="icon-container">
            <i class="el-icon-chat-line-round"></i>
          </div>
          <h3>智能对话</h3>
          <p>自然语言交互，专业汽车知识库支持</p>
        </div>
        
        <div class="feature-card">
          <div class="icon-container">
            <i class="el-icon-s-cooperation"></i>
          </div>
          <h3>个性化推荐</h3>
          <p>基于您的需求智能分析，推荐最合适的车型</p>
        </div>
        
        <div class="feature-card">
          <div class="icon-container">
            <i class="el-icon-time"></i>
          </div>
          <h3>24小时服务</h3>
          <p>全天候服务，随时解答您的购车疑问</p>
        </div>
      </div>
      
      <div class="preview-section">
        <div class="model-container">
          <div v-if="loading" class="loading-overlay">
            <div class="icon-container">
              <i class="el-icon-loading"></i>
            </div>
            <p>正在加载3D数字人模型...</p>
          </div>
          <canvas ref="modelCanvas" class="model-canvas"></canvas>
        </div>
        <div class="preview-info">
          <h2>数字人助手预览</h2>
          <p>我们的数字人助手正在紧张开发中，即将为您带来革命性的购车咨询体验。数字人助手将具备专业的汽车知识，能够回答您关于车型、配置、价格等各方面的问题，并根据您的需求为您提供个性化的推荐。</p>
          <p>同时，数字人助手还能够通过3D虚拟形象与您进行面对面交流，提供如同真人销售顾问般的互动体验，但不会有任何销售压力，让您轻松愉快地选择心仪的车辆。</p>
          <div class="model-controls">
            <el-button type="primary" size="small" @click="rotateModel('left')">
              <i class="el-icon-arrow-left"></i> 向左旋转
            </el-button>
            <el-button type="primary" size="small" @click="rotateModel('right')">
              向右旋转 <i class="el-icon-arrow-right"></i>
            </el-button>
            <el-button type="success" size="small" @click="zoomModel('in')">
              <i class="el-icon-zoom-in"></i> 放大
            </el-button>
            <el-button type="success" size="small" @click="zoomModel('out')">
              <i class="el-icon-zoom-out"></i> 缩小
            </el-button>
            <el-button 
              type="danger" 
              size="small" 
              @click="toggleAnimation"
              :icon="isAnimationPlaying ? 'el-icon-video-pause' : 'el-icon-video-play'"
            >
              {{ isAnimationPlaying ? '暂停动画' : '播放动画' }}
            </el-button>
          </div>
          
          <div class="conversation-panel">
            <div class="voice-controls">
              <el-button 
                type="primary" 
                @click="toggleRecording" 
                :disabled="isProcessing && !isRecording"
              >
                {{ isRecording ? '停止录音' : '开始录音' }}
              </el-button>
            </div>
            
            <div v-if="isRecording" class="recording-indicator">
              正在录音... {{ recordingTime }}秒
            </div>
            
            <div v-if="isProcessing" class="processing-indicator">
              正在处理...
            </div>
            
            <div v-if="transcriptionResult" class="transcription-result">
              <h3>识别结果:</h3>
              <p>{{ transcriptionResult }}</p>
            </div>
            
            <div v-if="aiResponse" class="ai-response">
              <h3>数字人回复:</h3>
              <p>{{ aiResponse }}</p>
            </div>
          </div>
          <div class="action-controls">
            <h3>数字人动作控制</h3>
            <div class="action-buttons">
              <el-button type="warning" @click="playAnimation('idle')">站立</el-button>
              <el-button type="warning" @click="playAnimation('bow')">鞠躬</el-button>
              <el-button type="warning" @click="playAnimation('sit')">坐下</el-button>
              <el-button type="warning" @click="playAnimation('sleep')">睡觉</el-button>
              <el-button type="warning" @click="playAnimation('wave')">挥手</el-button>
              <el-button type="warning" @click="playAnimation('walk')">行走</el-button>
              <el-button type="warning" @click="playAnimation('dance')">跳舞</el-button>
              <el-button type="warning" @click="playAnimation('talk')">说话</el-button>
            </div>
          </div>
          <div class="timeline">
            <div class="timeline-item">
              <div class="time">2023年12月</div>
              <div class="event">alpha测试版</div>
            </div>
            <div class="timeline-item">
              <div class="time">2024年3月</div>
              <div class="event">beta公测版</div>
            </div>
            <div class="timeline-item">
              <div class="time">2024年6月</div>
              <div class="event">正式上线</div>
            </div>
          </div>
        </div>
      </div>
      
      <div class="subscription-section">
        <h2>抢先体验</h2>
        <p>留下您的联系方式，我们将邀请您参与数字人助手的早期测试计划。</p>
        <div class="subscription-form">
          <el-form ref="form" :model="form" :rules="rules" label-width="80px">
            <el-form-item label="姓名" prop="name">
              <el-input v-model="form.name" placeholder="请输入您的姓名"></el-input>
            </el-form-item>
            <el-form-item label="邮箱" prop="email">
              <el-input v-model="form.email" placeholder="请输入您的邮箱"></el-input>
            </el-form-item>
            <el-form-item label="电话" prop="phone">
              <el-input v-model="form.phone" placeholder="请输入您的电话"></el-input>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="submitForm">提交申请</el-button>
            </el-form-item>
          </el-form>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import axios from 'axios'

export default {
  name: 'DigitalHuman',
  setup() {
    const modelCanvas = ref(null)
    const loading = ref(true)
    const isAnimationPlaying = ref(false)
    const isRecording = ref(false)
    const isProcessing = ref(false)
    const recordingTime = ref(0)
    const transcriptionResult = ref('')
    const aiResponse = ref('')
    const audioChunks = ref([])
    
    let mediaRecorder = null
    let recordingTimer = null
    
    // Three.js 相关变量
    let scene, camera, renderer, controls
    let model = null
    let mixer = null
    let clock = null
    let animationAction = null
    let animationsMap = null
    let actionMap = null
    
    // 初始化 Three.js 场景
    const initThreeJS = () => {
      try {
        // 创建场景
        scene = new THREE.Scene()
        scene.background = new THREE.Color(0xf5f5f5)
        
        // 创建相机
        camera = new THREE.PerspectiveCamera(
          45,
          modelCanvas.value.clientWidth / modelCanvas.value.clientHeight,
          0.1,
          1000
        )
        camera.position.set(0, 1.5, 4)
        
        // 创建渲染器
        renderer = new THREE.WebGLRenderer({
          canvas: modelCanvas.value,
          antialias: true,
          alpha: true
        })
        renderer.setSize(modelCanvas.value.clientWidth, modelCanvas.value.clientHeight)
        renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
        renderer.outputEncoding = THREE.sRGBEncoding
        renderer.shadowMap.enabled = true
        
        // 添加光源
        addLights()
        
        // 控制器
        controls = new OrbitControls(camera, renderer.domElement)
        controls.enableDamping = true
        controls.dampingFactor = 0.05
        controls.minDistance = 2
        controls.maxDistance = 10
        controls.target.set(0, 1, 0)
        controls.update()
        
        // 加载模型
        loadModel()
        
        // 初始化时钟
        clock = new THREE.Clock()
        
        // 处理窗口大小变化
        window.addEventListener('resize', onWindowResize)
        
        // 启动动画循环
        animate()
      } catch (error) {
        console.error('初始化3D场景失败:', error)
        loading.value = false
      }
    }
    
    // 添加光源
    const addLights = () => {
      // 环境光
      const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
      scene.add(ambientLight)
      
      // 前方主光源
      const mainLight = new THREE.DirectionalLight(0xffffff, 1)
      mainLight.position.set(0, 2, 4)
      mainLight.castShadow = true
      scene.add(mainLight)
      
      // 后方填充光
      const fillLight = new THREE.DirectionalLight(0xffffff, 0.3)
      fillLight.position.set(0, 2, -4)
      scene.add(fillLight)
      
      // 左侧光源
      const leftLight = new THREE.DirectionalLight(0xffffff, 0.5)
      leftLight.position.set(-4, 1, 0)
      scene.add(leftLight)
      
      // 右侧光源
      const rightLight = new THREE.DirectionalLight(0xffffff, 0.5)
      rightLight.position.set(4, 1, 0)
      scene.add(rightLight)
    }
    
    // 加载模型
    const loadModel = () => {
      const loader = new GLTFLoader()
      
      loader.load('/models/3d_female.glb', (gltf) => {
        model = gltf.scene
        
        // 调整模型大小和位置
        model.scale.set(1.5, 1.5, 1.5)
        model.position.set(0, 0, 0)
        
        // 设置阴影
        model.traverse((node) => {
          if (node.isMesh) {
            node.castShadow = true
            node.receiveShadow = true
            
            // 提高材质质量
            if (node.material) {
              node.material = node.material.clone()
              node.material.needsUpdate = true
            }
          }
        })
        
        scene.add(model)
        
        // 设置动画混合器
        if (gltf.animations && gltf.animations.length > 0) {
          mixer = new THREE.AnimationMixer(model)
          
          // 创建动作映射
          animationsMap = new Map()
          
          // 记录所有可用的动画
          console.log("Available animations:", gltf.animations.map(a => a.name));
          
          // 将所有动画添加到动画映射中
          gltf.animations.forEach((clip) => {
            animationsMap.set(clip.name.toLowerCase(), mixer.clipAction(clip))
          })
          
          // 查找合适的闲置动画作为默认动画
          const findAnimation = (keywords) => {
            for (const key of keywords) {
              for (const [name, action] of animationsMap.entries()) {
                if (name.includes(key)) {
                  return action
                }
              }
            }
            return null
          }
          
          // 寻找闲置动画
          const idleAction = findAnimation(['idle', 'stand', 'static', 'default'])
          
          // 如果找到闲置动画，就播放它
          if (idleAction) {
            animationAction = idleAction
            // 默认不播放动画
            animationAction.stop();
          } else if (gltf.animations.length > 0) {
            // 否则使用第一个动画
            const firstAnim = gltf.animations[0].name.toLowerCase()
            animationAction = animationsMap.get(firstAnim)
            if (animationAction) {
              // 默认不播放动画
              animationAction.stop();
            }
          }
          
          // 创建更多动作的映射关系
          actionMap = {
            'idle': findAnimation(['idle', 'stand', 'static', 'default']),
            'bow': findAnimation(['bow', 'greet', 'respect']),
            'sit': findAnimation(['sit', 'sitting']),
            'sleep': findAnimation(['sleep', 'lay', 'lying']),
            'wave': findAnimation(['wave', 'hello', 'greeting']),
            'walk': findAnimation(['walk', 'walking']),
            'dance': findAnimation(['dance', 'dancing']),
            'talk': findAnimation(['talk', 'talking', 'speak'])
          }
          
          // 检查映射中哪些动作有效，哪些需要使用退回的动作
          Object.keys(actionMap).forEach((key) => {
            if (!actionMap[key]) {
              // 如果没有找到特定动作，使用idle动作或第一个动作作为退回
              actionMap[key] = idleAction || (gltf.animations.length > 0 ? 
                animationsMap.get(gltf.animations[0].name.toLowerCase()) : null)
            }
            // 确保所有动画初始化为停止状态
            if (actionMap[key]) {
              actionMap[key].stop();
            }
          })
        }
        
        loading.value = false
      }, 
      // 进度回调
      (xhr) => {
        console.log(`模型加载进度: ${Math.floor(xhr.loaded / xhr.total * 100)}%`)
      }, 
      // 错误回调
      (error) => {
        console.error('加载模型失败:', error)
        loading.value = false
      })
    }
    
    // 处理窗口大小变化
    const onWindowResize = () => {
      if (!camera || !renderer || !modelCanvas.value) return
      
      camera.aspect = modelCanvas.value.clientWidth / modelCanvas.value.clientHeight
      camera.updateProjectionMatrix()
      renderer.setSize(modelCanvas.value.clientWidth, modelCanvas.value.clientHeight)
    }
    
    // 动画循环
    const animate = () => {
      requestAnimationFrame(animate)
      
      if (controls) controls.update()
      
      // 更新动画混合器，只有当动画处于播放状态时才更新
      if (mixer && isAnimationPlaying.value) {
        const deltaTime = clock.getDelta()
        mixer.update(deltaTime)
      }
      
      // 缓慢旋转模型 - 关闭自动旋转，使用控制器控制
      if (model && !controls.enableRotate && false) {
        model.rotation.y += 0.005
      }
      
      if (renderer && scene && camera) {
        renderer.render(scene, camera)
      }
    }
    
    // 控制模型旋转
    const rotateModel = (direction) => {
      if (!model) return
      
      const rotationAmount = direction === 'left' ? -Math.PI / 4 : Math.PI / 4
      model.rotation.y += rotationAmount
    }
    
    // 控制模型缩放
    const zoomModel = (direction) => {
      if (!camera) return
      
      const zoomAmount = direction === 'in' ? -1 : 1
      camera.position.z += zoomAmount
      
      // 限制缩放范围
      if (camera.position.z < 2) camera.position.z = 2
      if (camera.position.z > 10) camera.position.z = 10
    }
    
    // 播放指定动画
    const playAnimation = (actionKey) => {
      if (!mixer || !actionMap || !actionMap[actionKey]) {
        console.warn(`Animation for ${actionKey} not found`);
        return;
      }
      
      // 记录当前正在播放的动作
      const currentAnimation = animationAction;
      // 获取要播放的新动作
      const newAnimation = actionMap[actionKey];
      
      // 如果当前有动作在播放，并且不是要切换的新动作
      if (currentAnimation && currentAnimation !== newAnimation) {
        // 淡出当前动作
        currentAnimation.fadeOut(0.5);
      }
      
      // 淡入并播放新动作，只有在动画开启状态才实际播放
      newAnimation.reset()
      newAnimation.fadeIn(0.5)
      
      if (isAnimationPlaying.value) {
        newAnimation.play()
      }
      
      // 更新当前动作引用
      animationAction = newAnimation;
      
      // 动作提示反馈
      actionFeedback(actionKey);
    }
    
    // 切换动画播放状态
    const toggleAnimation = () => {
      isAnimationPlaying.value = !isAnimationPlaying.value;
      
      if (isAnimationPlaying.value) {
        // 播放当前动画
        if (animationAction) {
          animationAction.play();
        }
        actionFeedback('play');
      } else {
        // 暂停当前动画
        if (animationAction) {
          animationAction.stop();
        }
        actionFeedback('pause');
      }
    }
    
    // 动作反馈显示
    const actionFeedback = (actionKey) => {
      const actionMessages = {
        'idle': '数字人助手正在待命...',
        'bow': '数字人助手向您鞠躬致敬！',
        'sit': '数字人助手坐下来休息一会...',
        'sleep': '数字人助手进入休眠模式...',
        'wave': '数字人助手向您挥手问好！',
        'walk': '数字人助手正在行走...',
        'dance': '数字人助手为您表演舞蹈！',
        'talk': '数字人助手正在与您交谈...',
        'play': '开始播放动画',
        'pause': '暂停动画播放'
      };
      
      // 使用Element UI的消息提示
      if (window.ElMessage) {
        window.ElMessage({
          message: actionMessages[actionKey] || `执行动作: ${actionKey}`,
          type: 'success',
          duration: 2000
        });
      }
    }
    
    // 设置音频录制器
    const setupAudioRecorder = async () => {
      try {
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
        
        // 尝试使用更好的音频格式
        const options = {}
        if (MediaRecorder.isTypeSupported('audio/wav')) {
          options.mimeType = 'audio/wav'
        } else if (MediaRecorder.isTypeSupported('audio/webm')) {
          options.mimeType = 'audio/webm'
        }
        
        mediaRecorder = new MediaRecorder(stream, options)
        
        // 当有录音数据可用时
        mediaRecorder.ondataavailable = (event) => {
          if (event.data.size > 0) {
            audioChunks.value.push(event.data)
          }
        }
        
        // 录音停止时处理数据
        mediaRecorder.onstop = () => {
          processRecording()
        }
        
        console.log('音频录制器已设置，使用MIME类型:', mediaRecorder.mimeType)
      } catch (error) {
        console.error('设置音频录制器时出错:', error)
        window.ElMessage.error('无法访问麦克风，请确保已授予权限。')
      }
    }

    // 切换录音状态
    const toggleRecording = () => {
      if (isRecording.value) {
        stopRecording()
      } else {
        startRecording()
      }
    }

    // 开始录音
    const startRecording = async () => {
      try {
        transcriptionResult.value = ''
        aiResponse.value = ''
        audioChunks.value = []
        isRecording.value = true
        recordingTime.value = 0
        
        // 设置动画为说话状态
        playAnimation('talk')
        
        // 开始录音
        mediaRecorder.start(100)
        
        // 开始计时
        recordingTimer = setInterval(() => {
          recordingTime.value++
        }, 1000)
        
      } catch (error) {
        console.error('开始录音失败:', error)
        isRecording.value = false
        window.ElMessage.error('开始录音失败: ' + error.message)
      }
    }

    // 停止录音
    const stopRecording = () => {
      if (mediaRecorder && mediaRecorder.state !== 'inactive') {
        mediaRecorder.stop()
      }
      
      isRecording.value = false
      clearInterval(recordingTimer)
    }

    // 处理录音数据
    const processRecording = async () => {
      if (audioChunks.value.length === 0) return
      
      isProcessing.value = true
      
      try {
        // 创建一个FormData对象
        const formData = new FormData()
        
        // 将录音数据作为文件添加到FormData
        const audioBlob = new Blob(audioChunks.value, { type: 'audio/wav' })
        formData.append('file', audioBlob, 'recording.wav')
        
        // 添加参数
        formData.append('useLocalStorage', 'true')
        
        // 发送录音数据到后端进行处理
        const response = await axios.post('http://localhost:9999/api/voice/transcribe', formData, {
          headers: {
            'Content-Type': 'multipart/form-data'
          }
        })
        
        // 处理响应数据
        let recognizedText = ''
        try {
          if (typeof response.data === 'string') {
            // 尝试解析JSON字符串
            const jsonData = JSON.parse(response.data)
            
            // 检查是否有错误信息
            if (jsonData.error) {
              transcriptionResult.value = jsonData.error
              return
            }
            
            recognizedText = jsonData.text || jsonData
          } else {
            // 如果已经是对象，直接使用
            if (response.data.error) {
              transcriptionResult.value = response.data.error
              return
            }
            
            recognizedText = response.data.text || response.data
          }
        } catch (e) {
          // 如果不是JSON，直接使用原始文本
          recognizedText = response.data
        }
        
        transcriptionResult.value = recognizedText
        
        // 调用AI接口获取回复
        const aiResponseData = await axios.get('http://localhost:9999/ai/ollama', {
          params: {
            message: recognizedText
          }
        })
        
        aiResponse.value = aiResponseData.data || '抱歉，我无法回答这个问题。'
        
        // 调用文字转语音接口 - 修改为使用新的接口
        try {
          // 创建请求数据
          const ttsRequestData = {
            tts_text: aiResponse.value,
            mode: '预训练音色',
            speed: 1.0,
            sft_speaker: '中文女'
          }
          
          // 调用新的文字转语音接口
          const ttsResponse = await axios.post('http://localhost:8233/tts', ttsRequestData, {
            responseType: 'blob'
          })
          
          // 创建音频URL并播放
          const blob = new Blob([ttsResponse.data], { type: 'audio/wav' })
          
          console.log('音频数据大小:', blob.size, '字节')
          if (blob.size < 1000) {
            window.ElMessage.warning('生成的音频数据异常，可能不完整')
            toggleAnimation()
            return
          }
          
          const audioUrl = URL.createObjectURL(blob)
          const audio = new Audio(audioUrl)
          
          // 在回放语音时切换到说话动画
          audio.onplay = () => {
            toggleAnimation()
          }
          
          // 语音播放结束后切换回默认动画
          audio.onended = () => {
            toggleAnimation()
            // 音频播放完成后释放资源
            URL.revokeObjectURL(audioUrl)
          }
          
          // 播放错误处理
          audio.onerror = (e) => {
            console.error('音频播放错误:', e)
            window.ElMessage.error('音频加载失败，请重试')
            toggleAnimation()
            URL.revokeObjectURL(audioUrl)
          }
          
          // 播放音频
          audio.play().catch(error => {
            console.error('播放音频失败:', error)
            window.ElMessage.warning('自动播放失败，请允许网站自动播放音频')
            toggleAnimation()
          })
        } catch (ttsError) {
          console.error('文字转语音失败:', ttsError)
          window.ElMessage.error('生成语音失败: ' + ttsError.message)
          playAnimation('idle')
        }
        
      } catch (error) {
        console.error('处理录音失败:', error)
        window.ElMessage.error('处理录音失败: ' + error.message)
        // 发生错误时确保回到待机状态
        playAnimation('idle')
      } finally {
        isProcessing.value = false
      }
    }
    
    onMounted(() => {
      // 延迟初始化，确保DOM已渲染
      setTimeout(() => {
        initThreeJS()
        setupAudioRecorder()
      }, 100)
    })
    
    onBeforeUnmount(() => {
      // 清理资源
      if (renderer) {
        renderer.dispose()
      }
      
      if (controls) {
        controls.dispose()
      }
      
      window.removeEventListener('resize', onWindowResize)
      
      // 停止动画循环
      if (animationAction) {
        animationAction.stop()
      }
      
      scene = null
      camera = null
      renderer = null
      controls = null
      model = null
      mixer = null
      clock = null
      
      // 停止录音
      if (mediaRecorder && mediaRecorder.state !== 'inactive') {
        mediaRecorder.stop()
      }
      
      // 清理录音相关资源
      if (mediaRecorder && mediaRecorder.stream) {
        mediaRecorder.stream.getTracks().forEach(track => track.stop())
      }
      
      clearInterval(recordingTimer)
    })
    
    return {
      modelCanvas,
      loading,
      isAnimationPlaying,
      isRecording,
      isProcessing,
      recordingTime,
      transcriptionResult,
      aiResponse,
      rotateModel,
      zoomModel,
      playAnimation,
      toggleAnimation,
      toggleRecording
    }
  },
  data() {
    return {
      form: {
        name: '',
        email: '',
        phone: ''
      },
      rules: {
        name: [
          { required: true, message: '请输入姓名', trigger: 'blur' }
        ],
        email: [
          { required: true, message: '请输入邮箱', trigger: 'blur' },
          { type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
        ],
        phone: [
          { required: true, message: '请输入电话', trigger: 'blur' },
          { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
        ]
      }
    }
  },
  methods: {
    submitForm() {
      this.$refs.form.validate((valid) => {
        if (valid) {
          // TODO: 向后端发送数据
          this.$message.success('提交成功，我们会尽快与您联系！')
          this.resetForm()
        } else {
          return false
        }
      })
    },
    resetForm() {
      this.$refs.form.resetFields()
    }
  }
}
</script>

<style scoped>
.digital-human-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 40px 20px;
}

.header-section {
  text-align: center;
  margin-bottom: 60px;
  position: relative;
}

.title {
  font-size: 42px;
  color: #333;
  margin-bottom: 10px;
}

.development-badge {
  background-color: #E6A23C;
  color: white;
  padding: 6px 12px;
  border-radius: 4px;
  font-size: 16px;
  display: inline-block;
  margin-bottom: 20px;
}

.subtitle {
  font-size: 18px;
  color: #666;
  max-width: 800px;
  margin: 0 auto;
}

.feature-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 30px;
  margin-bottom: 60px;
}

.feature-card {
  background: white;
  border-radius: 10px;
  padding: 30px;
  text-align: center;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  transition: transform 0.3s, box-shadow 0.3s;
}

.feature-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
}

.icon-container {
  width: 70px;
  height: 70px;
  border-radius: 50%;
  background-color: #409EFF;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 20px;
}

.icon-container i {
  font-size: 32px;
  color: white;
}

.feature-card h3 {
  font-size: 20px;
  margin-bottom: 10px;
  color: #333;
}

.feature-card p {
  color: #666;
  line-height: 1.6;
}

.preview-section {
  display: flex;
  flex-direction: column;
  gap: 40px;
  margin-bottom: 60px;
}

.model-container {
  position: relative;
  width: 100%;
  height: 500px;
  background-color: #f5f5f5;
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
}

.model-canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(255, 255, 255, 0.8);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  z-index: 10;
}

.loading-overlay i {
  font-size: 40px;
  color: #409EFF;
  margin-bottom: 20px;
  animation: spin 2s linear infinite;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.preview-info {
  padding: 20px;
}

.preview-info h2 {
  font-size: 28px;
  color: #333;
  margin-bottom: 20px;
}

.preview-info p {
  font-size: 16px;
  color: #666;
  line-height: 1.8;
  margin-bottom: 20px;
}

.model-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 20px 0;
}

.model-controls .el-button {
  min-width: 120px;
}

.model-controls .el-button--primary {
  background-color: #409EFF;
  border-color: #409EFF;
}

.model-controls .el-button--primary:hover {
  background-color: #66b1ff;
  border-color: #66b1ff;
}

.model-controls .el-button--danger {
  background-color: #F56C6C;
  border-color: #F56C6C;
}

.model-controls .el-button--danger:hover {
  background-color: #f78989;
  border-color: #f78989;
}

.model-controls .el-button.is-loading {
  opacity: 0.8;
  cursor: not-allowed;
}

.model-controls .el-button.is-disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.action-controls {
  margin: 20px 0;
}

.action-controls h3 {
  margin-bottom: 15px;
  color: #333;
  font-size: 18px;
}

.action-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.timeline {
  display: flex;
  justify-content: space-between;
  margin-top: 40px;
  padding: 20px 0;
  border-top: 1px solid #eee;
  border-bottom: 1px solid #eee;
}

.timeline-item {
  text-align: center;
  flex: 1;
}

.time {
  font-weight: bold;
  color: #409EFF;
  margin-bottom: 10px;
}

.event {
  color: #333;
}

.subscription-section {
  text-align: center;
  padding: 50px;
  background-color: #f9f9f9;
  border-radius: 10px;
}

.subscription-section h2 {
  font-size: 28px;
  color: #333;
  margin-bottom: 20px;
}

.subscription-section p {
  font-size: 16px;
  color: #666;
  margin-bottom: 30px;
  max-width: 700px;
  margin-left: auto;
  margin-right: auto;
}

.subscription-form {
  max-width: 500px;
  margin: 0 auto;
}

.conversation-panel {
  margin-top: 30px;
  padding: 20px;
  background-color: #f9f9f9;
  border-radius: 10px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.voice-controls {
  display: flex;
  justify-content: center;
  margin-bottom: 15px;
}

.voice-controls .el-button {
  padding: 12px 25px;
  font-size: 16px;
}

.recording-indicator {
  color: #ff0000;
  font-weight: bold;
  margin: 10px 0;
  text-align: center;
  animation: blink 1s infinite;
}

.processing-indicator {
  color: #0066cc;
  font-weight: bold;
  margin: 10px 0;
  text-align: center;
}

.transcription-result,
.ai-response {
  margin-top: 20px;
  padding: 15px;
  border-radius: 8px;
}

.transcription-result {
  background-color: #e9f7ef;
  border-left: 4px solid #4CAF50;
}

.ai-response {
  background-color: #e6f3ff;
  border-left: 4px solid #1976d2;
}

.transcription-result h3,
.ai-response h3 {
  margin-top: 0;
  font-size: 18px;
}

.transcription-result p,
.ai-response p {
  margin-bottom: 0;
  line-height: 1.6;
}

@keyframes blink {
  50% {
    opacity: 0.5;
  }
}

@media (max-width: 768px) {
  .preview-section {
    flex-direction: column;
  }
  
  .model-container {
    height: 400px;
  }
  
  .timeline {
    flex-direction: column;
    gap: 20px;
  }
}
</style> 